package de.mmis.core.base.event;

import java.util.ArrayList;
import java.util.HashMap;

import org.apache.log4j.Logger;

import de.mmis.core.base.abstracttree.Tree;
import de.mmis.core.base.abstracttree.serializer.DeserializableException;
import de.mmis.core.base.abstracttree.serializer.SerializerHelper;
import de.mmis.core.base.gclass.GClass;

/**
 * auxiliary class used for objects implementing the Observable interface to
 * create parameterized generic observer although type information is erased at
 * runtime
 * 
 * @author Christian Koch
 */
@SuppressWarnings({ "unchecked", "rawtypes" })
public class GenericObservable implements Observable {

	private final static Logger LOGGER = Logger
			.getLogger(GenericObservable.class);

	private ArrayList<Observer> observers = new ArrayList<Observer>();

	private GClass clazz;
	private ClassLoader classLoader;

	/**
	 * creates new parameterized Observer of given type
	 * 
	 * @param clazz
	 *            type of generic Observer that should be created
	 */
	public GenericObservable(GClass clazz) {
		this(clazz, clazz.getCommonClassLoader());
	}

	/**
	 * creates new parameterized Observer of given type
	 * 
	 * @param clazz
	 *            type of generic Observer that should be created
	 */
	public GenericObservable(GClass clazz, ClassLoader classLoader) {
		this.clazz = clazz;
		this.classLoader = classLoader;
	}

	/**
	 * @return type of generic Observer
	 */
	public GClass getClazz() {
		return this.clazz;
	}

	/**
	 * add new observer to list
	 * 
	 * @param obs
	 *            observer to add
	 */
	@Override
	public void addObserver(Observer obs) {
		synchronized (observers) {
			this.observers.add(obs);
		}
	}

	/**
	 * remove observer from list
	 * 
	 * @param obs
	 *            observer to remove
	 */
	@Override
	public void removeObserver(Observer obs) {
		synchronized (observers) {
			this.observers.remove(obs);
		}
	}

	/**
	 * send event to all observers
	 * 
	 * @param event
	 *            event to send
	 */
	public void fireEvent(Tree event) {
		try {
			Event eventobj = (Event) SerializerHelper
					.deserializeObject(event, this.clazz, this.classLoader,
							new HashMap<String, Object>());

			synchronized (observers) {
				for (Observer observer : this.observers) {
					observer.notify(null, eventobj);
				}
			}

		} catch (DeserializableException e) {
			LOGGER.error("cannot deserialize event Tree", e);
		}
	}
}
